package com.aliyun.order.server.service.impl;

import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSON;

import com.aliyun.commons.dlock.DistributedLock;
import com.aliyun.commons.dlock.DistributedLock.LockResult;
import com.aliyun.commons.model.Result;
import com.aliyun.commons.service.SendMessageService;
import com.aliyun.flashsale.client.model.FlashSaleProductDTO;
import com.aliyun.flashsale.client.service.FlashSaleProductService;
import com.aliyun.inventory.client.service.InventoryService;
import com.aliyun.order.client.constants.OrderStatus;
import com.aliyun.order.client.model.CreateOrderRequest;
import com.aliyun.order.client.model.OrderDetailDTO;
import com.aliyun.order.client.model.OrderDetailDTO.OrderItemDTO;
import com.aliyun.order.client.service.OrderService;
import com.aliyun.order.server.dao.entity.OrderDO;
import com.aliyun.order.server.dao.entity.OrderItemDO;
import com.aliyun.order.server.dao.mapper.OrderItemMapper;
import com.aliyun.order.server.dao.mapper.OrderMapper;
import com.aliyun.product.client.constants.ProductStatus;
import com.aliyun.product.client.model.ProductDTO;
import com.aliyun.product.client.service.ProductService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * 商品服务实装
 *
 * 
 * @date 2024/11/27
 */
@Slf4j
@DubboService
public class OrderServiceImpl implements OrderService {

    @DubboReference
    private ProductService productService;
    @DubboReference
    private InventoryService inventoryService;
    @DubboReference
    private FlashSaleProductService flashSaleProductService;
    @Autowired
    private DistributedLock distributedLock;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderItemMapper orderItemMapper;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private SendMessageService sendMessageService;
    @Value("${rocketmq.order-fail-after-deducted-inventory-topic}")
    private String failTopic;
    @Value("${rocketmq.order-success-topic}")
    private String successTopic;

    @Override
    public Result<Long> createOrder(CreateOrderRequest request) {
        // 参数校验
        FlashSaleProductDTO flashSaleProductDTO = validateParams(request);

        // 下单-加锁执行，同一用户任何时刻仅能进行一次下单操作
        String lockKey = "CREATE_ORDER_" + request.getUserId() + "_" + request.getProductId();
        LockResult<Result<Long>> result = distributedLock.executeWithLock(lockKey, 10,
            () -> execute(request, flashSaleProductDTO.getFlashSalePrice()));
        if (!result.isSuccess()) {
            return Result.fail("USER_ORDER_FREQUENCY_TOO_HIGH", "您的下单过于频繁，请稍候重试");
        }
        return result.getData();
    }

    @Override
    public Result<OrderDetailDTO> getOrderDetail(long orderId) {
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (orderDO == null) {
            return Result.fail("ORDER_NOT_FOUND", "订单不存在");
        }
        QueryWrapper<OrderItemDO> queryWrapper = new QueryWrapper<>(OrderItemDO.class).eq("order_id", orderId);
        List<OrderItemDO> orderItemDOS = orderItemMapper.selectList(queryWrapper);
        return Result.success(toOrderDetailDTO(orderDO, orderItemDOS));
    }

    /**
     * 验证参数
     *
     * @param request 请求
     * @return {@link Result }<{@link Long }>
     */
    private FlashSaleProductDTO validateParams(CreateOrderRequest request) {
        if (request.getQuantity() <= 0) {
            throw new IllegalArgumentException("购买数量必须大于0");
        }
        // 商品信息查询&校验
        Result<ProductDTO> productResult = productService.getProduct(request.getProductId());
        if (!productResult.isSuccess() || productResult.getData() == null) {
            throw new IllegalArgumentException("商品不存在");
        }
        ProductDTO productDTO = productResult.getData();
        if (ProductStatus.ONLINE.getValue() != productDTO.getStatus()) {
            throw new IllegalArgumentException("商品已下架");
        }
        // 秒杀商品信息查询&校验
        Result<FlashSaleProductDTO> saleProductDTOResult = flashSaleProductService.getFlashSaleProduct(
            request.getFlashSaleProductId());
        if (!saleProductDTOResult.isSuccess() || saleProductDTOResult.getData() == null) {
            throw new IllegalArgumentException("秒杀商品不存在");
        }
        FlashSaleProductDTO saleProductDTO = saleProductDTOResult.getData();
        Date now = new Date();
        if (saleProductDTO.getStartTime().after(now) || saleProductDTO.getEndTime().before(now)) {
            throw new IllegalArgumentException("当前不在秒杀活动时间内");
        }
        return saleProductDTOResult.getData();
    }

    /**
     * 执行
     *
     * @param request   请求
     * @param salePrice 商品 价格
     * @return {@link Result }<{@link Long }>
     */
    private Result<Long> execute(CreateOrderRequest request, Long salePrice) {
        // 扣除库存
        Result<Void> deductInventoryResult = inventoryService.deductInventory(request.getUserId(),
            request.getProductId(), request.getQuantity());
        if (!deductInventoryResult.isSuccess()) {
            return Result.fail(deductInventoryResult.getCode(), deductInventoryResult.getMessage());
        }

        // 创建订单
        long orderId = 0;
        try {
            orderId = createOrder(request, salePrice);
        } catch (Exception e) {
            log.error("create order failed, request={} message={}", JSON.toJSONString(request), e.getMessage(), e);
            // 发送失败消息
            sendFailMessage(request);
            return Result.fail("CREATE_ORDER_FAILED", "创建订单失败");
        }
        return Result.success(orderId);
    }

    /**
     * 发送异步消息
     *
     * @param request 请求
     */
    private void sendFailMessage(CreateOrderRequest request) {
        String messageKey = UUID.randomUUID() + "_" + request.getUserId() + "_" + request.getProductId();
        sendMessageService.sendAsyncMessage(failTopic, null, messageKey, JSON.toJSONString(request));
    }

    /**
     * 订购详细信息 DTO
     *
     * @param orderDO
     * @param orderItemDOS
     * @return {@link OrderDetailDTO }
     */
    private OrderDetailDTO toOrderDetailDTO(OrderDO orderDO, List<OrderItemDO> orderItemDOS) {
        OrderDetailDTO orderDetailDTO = new OrderDetailDTO();
        orderDetailDTO.setOrderId(orderDO.getId());
        orderDetailDTO.setGmtCreate(orderDO.getGmtCreate());
        orderDetailDTO.setUserId(orderDO.getUserId());
        orderDetailDTO.setAmount(orderDO.getAmount());
        orderDetailDTO.setStatus(orderDO.getStatus());
        orderDetailDTO.setCloseTime(orderDO.getCloseTime());
        orderDetailDTO.setOrderItemDTOList(
            orderItemDOS.stream().map(this::toOrderItemDTO).collect(Collectors.toList()));
        return orderDetailDTO;
    }

    /**
     * 订购商品 DTO
     *
     * @param orderItemDO 次序项目实体
     * @return {@link OrderItemDTO }
     */
    private OrderItemDTO toOrderItemDTO(OrderItemDO orderItemDO) {
        OrderItemDTO orderItemDTO = new OrderItemDTO();
        orderItemDTO.setOrderItemId(orderItemDO.getId());
        orderItemDTO.setGmtCreate(orderItemDO.getGmtCreate());
        orderItemDTO.setAmount(orderItemDO.getAmount());
        orderItemDTO.setOrderId(orderItemDO.getOrderId());
        orderItemDTO.setProductId(orderItemDO.getProductId());
        orderItemDTO.setQuantity(orderItemDO.getQuantity());
        return orderItemDTO;
    }

    /**
     * 创建订单
     *
     * @param request   请求
     * @param salePrice 商品价格
     * @return long
     */
    private long createOrder(CreateOrderRequest request, Long salePrice) throws Exception {
        String messageKey = UUID.randomUUID() + "_" + request.getUserId() + "_" + request.getProductId();
        // 发送事务消息，确保本地创建订单的事务和发送消息的一致性
        return sendMessageService.sendTransactionMessage(successTopic, null, messageKey, JSON.toJSONString(request),
            (messageId) -> {
                // 本地事务执行订单创建
                return transactionTemplate.execute(t -> {
                    // 创建订单
                    OrderDO order = new OrderDO();
                    order.setUniqueKey(messageId);
                    order.setUserId(request.getUserId());
                    long totalAmount = request.getQuantity() * salePrice;
                    order.setAmount(totalAmount);
                    order.setStatus(OrderStatus.WAIT_PAYMENT.getValue());
                    Date now = new Date();
                    order.setGmtCreate(now);
                    orderMapper.insert(order);

                    // 创建订单明细
                    OrderItemDO orderItem = new OrderItemDO();
                    orderItem.setGmtCreate(now);
                    orderItem.setUserId(order.getUserId());
                    orderItem.setOrderId(order.getId());
                    orderItem.setProductId(request.getProductId());
                    orderItem.setQuantity(request.getQuantity());
                    orderItem.setAmount(totalAmount);
                    orderItemMapper.insert(orderItem);
                    return order.getId();
                });
            });
    }
}